package cc.mllt.demoaopmybatisauth.demos.web.service.impl;

import cc.mllt.demoaopmybatisauth.demos.web.model.entity.DataPermissionRule;
import cc.mllt.demoaopmybatisauth.demos.web.service.CacheDataService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 数据权限缓存服务实现类，提供数据范围规则和权限规则的缓存与读取功能。
 * <p>
 * 该类使用Redis作为缓存存储介质，数据范围规则以Hash结构存储，权限规则以有序集合（ZSet）存储，
 * </p>
 */
@Service
public class CacheDataServiceImpl implements CacheDataService {

    private static final Logger log = LoggerFactory.getLogger(CacheDataServiceImpl.class);

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 缓存用户的数据范围规则到Redis Hash结构
     * <p>
     * 在保存新规则前会清除该用户已有的缓存规则，避免数据残留。
     * 如果传入的规则集合为空，则直接返回不执行存储操作。
     * </p>
     *
     * @param userId          用户唯一标识
     * @param dataScopeRules 模块标识与数据权限规则的映射集合，
     *                       键为模块名（如"order","customer"），
     *                       值为对应的数据权限规则
     */
    @Override
    public void cacheDataScopeRules(String userId, Map<String, DataPermissionRule> dataScopeRules) {
        if (dataScopeRules == null || dataScopeRules.isEmpty()) {
            log.info("规则存储到Redis终止：无规则");
            return;
        }

        String cacheKey = getCacheKeyDataScope(userId);
        // 清空历史缓存数据
        redisTemplate.delete(cacheKey);

        redisTemplate.opsForHash().putAll(cacheKey, dataScopeRules);

        log.info("即将为用户 ID {} 保存数据范围规则到Redis", userId);
        dataScopeRules.forEach((module, rule) ->
                log.debug("模块: {}, 规则: {}", module, rule.getDataScope())
        );
    }

    /**
     * 从Redis获取用户的数据范围规则集合
     *
     * @param userId 用户唯一标识
     * @return 模块标识与数据权限规则的映射集合，
     *         当无缓存数据时返回空Map（非null）
     */
    @Override
    public Map<String, DataPermissionRule> getDataScopeRules(String userId) {
        String cacheKey = getCacheKeyDataScope(userId);
        Map<Object, Object> rawRules = redisTemplate.opsForHash().entries(cacheKey);

        Map<String, DataPermissionRule> rules = new HashMap<>();
        for (Map.Entry<Object, Object> entry : rawRules.entrySet()) {
            try {
                rules.put((String) entry.getKey(), (DataPermissionRule) entry.getValue());
            } catch (ClassCastException e) {
                log.error("数据范围规则类型转换失败: {}", entry);
            }
        }

        if (rules.isEmpty()) {
            log.info("用户 ID {} 无数据范围规则", userId);
        } else {
            log.info("成功获取用户 ID {} 的 {} 条数据范围规则", userId, rules.size());
        }
        return rules;
    }

    /**
     * 缓存用户权限规则到Redis有序集合（ZSet）
     * <p>
     * 规则按ruleWeight字段值排序，存储前会清除该用户已有规则缓存。
     * 空规则集合将不执行存储操作。
     * </p>
     *
     * @param userId 用户唯一标识
     * @param rules  待缓存的权限规则列表，按规则权重降序排列
     */
    @Override
    public void cacheRules(String userId, List<DataPermissionRule> rules) {
        if (rules == null || rules.isEmpty()) {
            log.info("权限规则存储到Redis终止：无规则");
            return;
        }

        String cacheKey = getCacheKeyRules(userId);
        // 清空历史缓存数据
        redisTemplate.delete(cacheKey);

        rules.forEach(rule ->
                redisTemplate.opsForZSet().add(cacheKey, rule, rule.getRuleWeight())
        );
        redisTemplate.expire(cacheKey, 72, TimeUnit.HOURS);
        log.info("已为用户 ID {} 缓存 {} 条权限规则到Redis", userId, rules.size());
    }

    /**
     * 从Redis获取用户权限规则列表（按权重降序排列）
     *
     * @param userId 用户唯一标识
     * @return 按权重降序排列的权限规则列表，
     *         当无缓存数据时返回空列表（非null）
     */
    @Override
    public List<DataPermissionRule> getRules(String userId) {
        String cacheKey = getCacheKeyRules(userId);
        Set<Object> ruleSet = redisTemplate.opsForZSet().reverseRange(cacheKey, 0, -1);

        List<DataPermissionRule> rules = new ArrayList<>();
        if (ruleSet != null) {
            ruleSet.forEach(obj -> {
                try {
                    rules.add((DataPermissionRule) obj);
                } catch (ClassCastException e) {
                    log.error("权限规则类型转换失败: {}", obj);
                }
            });
        }

        if (rules.isEmpty()) {
            log.info("用户 ID {} 无权限规则", userId);
        } else {
            log.info("成功获取用户 ID {} 的 {} 条权限规则", userId, rules.size());
        }
        return rules;
    }

    /**
     * 生成数据范围规则的缓存键
     *
     * @param userId 用户ID
     * @return 格式为"dataScopeRules:userId"的字符串
     */
    private String getCacheKeyDataScope(String userId) {
        return "dataScopeRules:" + userId;
    }

    /**
     * 生成权限规则有序集合的缓存键
     *
     * @param userId 用户ID
     * @return 格式为"userRules:userId"的字符串
     */
    private String getCacheKeyRules(String userId) {
        return "userRules:" + userId;
    }
}